<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  
  <title>MySQL主从复制 | htop.me</title>
  <meta name="author" content="Zhaifg">
  
  <meta name="description" content="MySQL复制MySQL复制支持单向，异步复制。通过一台主服务器将更新写入二进制日志文件，并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时，它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新，然后封锁并">
  
  <meta name="keywords" content="MySQL">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <meta property="og:title" content="MySQL主从复制"/>
  <meta property="og:site_name" content="htop.me"/>

  
    <meta property="og:image" content="undefined"/>
  

  
  
    <link href="/favicon.png" rel="icon">
  
  
  <link rel="stylesheet" href="/css/bootstrap.min.css" media="screen" type="text/css">
  <link rel="stylesheet" href="/css/font-awesome.css" media="screen" type="text/css">
  <link rel="stylesheet" href="/css/style.css" media="screen" type="text/css">
  <link rel="stylesheet" href="/css/highlight.css" media="screen" type="text/css">
  <link rel="stylesheet" href="/css/google-fonts.css" media="screen" type="text/css">
  <!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->

  <script src="/js/jquery-2.0.3.min.js"></script>

  <!-- analytics -->
  


<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "//hm.baidu.com/hm.js?null";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>


</head>

 <body>  
  <nav id="main-nav" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
    <div class="container">
      <button type="button" class="navbar-header navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
		<span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
	  <a class="navbar-brand" href="/">htop.me</a>
      <div class="collapse navbar-collapse nav-menu">
		<ul class="nav navbar-nav">
		  
		  <li>
			<a href="/archives" title="All the articles.">
			  <i class="fa fa-archive"></i>Archives
			</a>
		  </li>
		  
		  <li>
			<a href="/Categories" title="All the categories.">
			  <i class="fa fa-folder"></i>Categories
			</a>
		  </li>
		  
		  <li>
			<a href="/Tags" title="All the tags.">
			  <i class="fa fa-tags"></i>Tags
			</a>
		  </li>
		  
		  <li>
			<a href="/about" title="About me.">
			  <i class="fa fa-user"></i>About
			</a>
		  </li>
		  
		</ul>
      </div>
    </div> <!-- container -->
</nav>
<div class="clearfix"></div>

  <div class="container">
  	<div class="content">
    	 


	
		<div class="page-header">		
			<h1> MySQL主从复制</h1>
		</div>		
	



<div class="row post">
	<!-- cols -->
	
	<div class="col-md-9">
	

			

	<!-- content -->
	<div class="mypage">		
	    <h2 id="MySQL复制">MySQL复制</h2><p>MySQL复制支持单向，异步复制。通过一台主服务器将更新写入二进制日志文件，并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时，它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新，然后封锁并等待主服务器通知新的更新。MySQL主从复制是异步进行的。同步需要版本为5.5,使用google提供的插件来实现。</p>
<p>MySQL主从复制操作很灵活既可以实现整个服务的级别的复制，也可以实现对某个库，甚至某个数据库中的指定的某个对象进行复制。</p>
<h2 id="MySQL主从复制应用场景">MySQL主从复制应用场景</h2><ol>
<li><p>提高性能。通过一(多)主多从的部署方案，将涉及数据写的操作放在Master端操作，而将数据读的操作分散到众多的Slave当中。降低了Master的负载，提高数据写入的响应效率；多台从服务器提供读，分担了请求，提高了读的效率。</p>
</li>
<li><p>数据安全。数据复制到Slave节点，即使Master宕机，Slave节点还保存着完整数据。</p>
</li>
<li><p>数据分析。将数据分析，放在slave上。</p>
</li>
</ol>
<h2 id="主从复制的原理">主从复制的原理</h2><p>MySQL的Replication是一个异步的复制过程，从一个MySQL实例(Master)复制到另一台MySQL实例上。在Master和Slave之间复制的整个过程主要由3个线程完成，其中两个线程（SQL线程和IO线程）在Slave端，另外一个线程(IO线程)在Master端。</p>
<p>要实现主从复制，首先要在Master端打开Binary Log功能。因为整个复制过程实际上就是Slave从Master上获取二进制日志，然后在自己身上完全按照产生的顺序一次执行日志中记录的各种操作的过程。</p>
<p>复制的具体过程如下：</p>
<p><img src="http://7xkabv.com1.z0.glb.clouddn.com/htop_mysql_replication.jpg" alt="MySQL主从复制原理图"></p>
<ol>
<li>Slave的IO线程连上Master，并请求日志文件指定位置(或从开始的日志)之后的日志的内容。</li>
<li>Master接收到来自Slave的IO线程请求后，负责复制IO线程根据请求的信息读取指定日志之后的日志信息，返回给Slave端的IO线程。返回信息中除了日志所包含的信息，还包含了包括本次返回的信息在Master端的Binary Log文件的名称和位置。</li>
<li>Slave的IO线程接受到信息后，将日志内容一次写入Slave端的Relay Log文件(mysql-relay-bin.xxxx)的末端，并将读取到的Master端的bin-log的文件和位置记录到master-info文件中，以便在下一次读取时能够清楚地告诉Master，下次从bin-log哪个位置开始往后的日志内容。</li>
<li>Slave的SQL线程检测检测到Relay Log中更新内容后，会马上解析该Log文件中的内容，还原成在Master端真实执行时的可执行的SQL语句，并执行这些SQK语句。实际上Master和Slave执行同样的语句。</li>
</ol>
<h2 id="Binary_Log_记录方式">Binary Log 记录方式</h2><h3 id="Row_Level">Row Level</h3><p>Binary Log会记录成每一行数据被修改的形式，然后在Slave端再对相同的数据进行修改。</p>
<p><strong>优点</strong>：在Row Level模式下，Binnary Log可以不记录执行的Query语句的上下文相关信息，只要记录哪一行修改了，修改成什么样子。Row Level会详细的记录下每一行数据的修改细节，而且不会出现某个特定情况下的存储过程，或Function，以及Trigger的调用和触发无法被正确复制问题。</p>
<p><strong>缺点</strong>：产生大量的日志内容。</p>
<h3 id="Statment_Level">Statment Level</h3><p>每一条会修改的SQL语句都会记录到Master的Binnary中。Slave端在复制的时候，SQL线程会解析成和原来Master端执行过相同的SQL语句，并再次执行。</p>
<p><strong>优点</strong>：首先，解决了Row Level下的缺点，不须要记录每一行的数据变化，减少了Binnary Log日志量，节约了IO成本，提高了性能。</p>
<p><strong>缺点</strong>：由于它是记录的执行语句，为了让这些语句在Slave端也能正确执行。那么它还必须记录每条语句在执行时的一些相关信息，即上下文信息，以保证所有语句在Slave端被执行的时候能够得到和在Master端执行时相同的结果。另外，由于MySQL发展比较快，很多新功能不断加入，使得MySQL复制遇到了不小的挑战，复制时设计的内容岳父在，越容易出bug。在Statement Level下，目前已发现不少的情况下会造成MySQL的复制问题。主要是在修改数据使用了某些特定的函数货功能后，出现，比如：Sleep()函数在有些版本中就不能正确的复制，在存储过程中使用了last_insert_id()函数，可能会使Slave和Master的到不一致的ID，等等。</p>
<h3 id="Mixed_Level">Mixed Level</h3><p>在Mixed模式下，MySQL会根据执行的每一条具体的SQL语句来区分对待记录的日志形式，也就是在Statement和Row之间选择一种。除了MySQL认为通过Statement方式可能造成复制过程中Master和Slave之间产生不一致数据。(如特殊Procedure和Funtion的使用，UUID()函数的使用等特殊情况)时，它会选择ROW的模式来记录变更之外，都会使用Statement方式。</p>
<h2 id="设置主从">设置主从</h2><p>主从设置的主要步骤是</p>
<ol>
<li>修改Master和Slave的my.cnf中的server-id，使之唯一,开启binlog。</li>
<li>若不停Master时，加入全局锁，记录bin-log文件和bin-log文件的位置，全备要同步的数据库；解除全局锁</li>
<li>若可以停库时，停止主库，物理备份所需要同步的数据库。</li>
<li>在Slave端恢复备份的数据。</li>
<li>用<code>change master</code>在Slave建立与master的联系。</li>
<li>启动Slave。</li>
<li>检查Slave的状态。</li>
</ol>
<h3 id="实例">实例</h3><ol>
<li>不停主库的建立主从复制。</li>
</ol>
<p><strong>第一部分 对主库的操作</strong></p>
<ul>
<li>1、修改主库的文件，开启MySQL的<code>bin-log</code>。（一般安装的时候最好先做好，这样可以不停库。）<br>修改主库的配置文件my.cnf：</li>
</ul>
<figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">vim  /etc/<span class="keyword">my</span>.cnf</span><br><span class="line"></span><br><span class="line">server-<span class="property">id</span> = <span class="number">1</span>         <span class="comment"># 设置server-id 确保id为唯一，最好用ip地址，后三位</span></span><br><span class="line">bin-<span class="command">log</span>=mysql-bin    <span class="comment"># 设置 bin-log，这地方可以指定为bin-log的目录？</span></span><br><span class="line"></span><br><span class="line">/etc/init.d/mysqld restart</span><br></pre></td></tr></table></figure>
<p>修改完成后，重启mysql</p>
<ul>
<li><p>2、登录主库，添加从库的同步账号。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mysql –uroot –p</span><br><span class="line"><span class="operator"><span class="keyword">grant</span>   replication   <span class="keyword">slave</span>  <span class="keyword">on</span>  *.*  <span class="keyword">to</span>  ‘rep’@’<span class="number">192.168</span>.0.%’  <span class="keyword">identified</span> <span class="keyword">by</span> ‘passwd’;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>3、对主库进行锁表操作，禁止更新，（为了防止备份时的数据不一致问题）。并查看bin-log的名字和日志的（position）。</p>
</li>
</ul>
<figure class="highlight asciidoc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">flush  tables with read lock；</span><br><span class="line">show master status；</span><br><span class="line"></span><br><span class="line"><span class="header">mysql&gt; show master status;</span><br><span class="line">+------------------+----------+--------------+------------------+</span></span><br><span class="line"><span class="header">| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |</span><br><span class="line">+------------------+----------+--------------+------------------+</span></span><br><span class="line"><span class="header">| mysql-bin.000107 | 38874616 |              |                  |</span><br><span class="line">+------------------+----------+--------------+------------------+</span></span><br><span class="line">1 row in set (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt;</span><br></pre></td></tr></table></figure>
<p>记录这两个值<br><code>mysql-bin.000107</code><br><code>38874616</code><br>取得<code>bin-log</code> 和 <code>position</code><br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql -uroot -p'yz11235' -<span class="keyword">e</span> <span class="string">"show master status"</span> | awk '&#123;<span class="keyword">if</span> (NR == 2)&#123; <span class="keyword">print</span> <span class="label">$1</span> <span class="string">"\n"</span> <span class="label">$2</span>;&#125;&#125;' &gt; temp.txt</span><br></pre></td></tr></table></figure></p>
<ul>
<li><p>4、对主库进行全备份。</p>
<figure class="highlight 1c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqldump  -h hostname -uroot -p’’ -A -B -F  <span class="string">| gzip &gt;alldb.sql.gz</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>5、导出数据库后，进行对数据库表解锁。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">unlock</span> <span class="keyword">tables</span></span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p><strong>第二部分 从库上操作</strong></p>
<ul>
<li><ol>
<li>在从库上设置my.cnf，设置server-id，和注释bin-log。<figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">server-<span class="property">id</span> = <span class="number">2</span></span><br><span class="line"><span class="comment"># bin-log = mysql-bin</span></span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
</ul>
<p>重启 mysql。</p>
<ul>
<li><p>2、登录从库，并设置从库信息</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">change</span> <span class="keyword">master</span> <span class="keyword">to</span></span><br><span class="line">master_host=<span class="string">'192.168.0.106'</span>,</span><br><span class="line">master_port=<span class="number">3306</span>,</span><br><span class="line">master_user=<span class="string">'rep'</span>,</span><br><span class="line">master_password=<span class="string">'111111'</span>,</span><br><span class="line">master_log_file=<span class="string">'mysql-bin.000107'</span>,</span><br><span class="line">master_log_pos=<span class="number">38907472</span>;</span></span><br><span class="line">mast_connect_retry=10;</span><br></pre></td></tr></table></figure>
</li>
<li><p>3、启动 从库</p>
</li>
</ul>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">start</span> <span class="keyword">slave</span></span></span><br></pre></td></tr></table></figure>
<ul>
<li>4、查看从库状态，<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">show</span> <span class="keyword">slave</span> <span class="keyword">status</span>\G</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>观察：<code>slave_IO_Running : Yes</code><br>      <code>Slave_SQL_Running : Yes</code><br>以上两个为Yes 说明主从已经成功。<br><code>Second_behind_master = 0</code> 这是从库落后主库的秒数。</p>
	  
	</div>

	<div>
  	<center>
	<div class="pagination">
<ul class="pagination">
	 
		
          <li class="prev disabled"><a><i class="fa fa-arrow-circle-o-left"></i>上一篇</a></li>
        

        <li><a href="/archives"><i class="fa fa-archive"></i>Archive</a></li>

		
		   <li class="next"><a href="/2015/07/07/服务器硬盘测试相关/" class="alignright next">下一篇<i class="fa fa-arrow-circle-o-right"></i></a></li>         
        
	
</ul>
</div>

    </center>
	</div>
	
	<!-- comment -->
	
<section id="comment">
  <h2 class="title">留言</h2>

  
  <!-- 多说评论框 start -->
  	 <div class="ds-thread" data-thread-key="2015/07/10/MySQL复制/" data-title="MySQL主从复制" data-url="http://htop.me/2015/07/10/MySQL复制/">


<!-- 多说评论框 end -->
<!-- 多说公共JS代码 start (一个网页只需插入一次) -->
<script type="text/javascript">
var duoshuoQuery = {short_name:"jenguo"};
    (function() {
        var ds = document.createElement('script');
        ds.type = 'text/javascript';ds.async = true;
        ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
        ds.charset = 'UTF-8';
        (document.getElementsByTagName('head')[0]
         || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
    </script>
<!-- 多说公共JS代码 end -->


     </div>
  
</section>

	
	</div> <!-- col-md-9/col-md-12 -->
	
	
		<div class="col-md-3"> 

	<!-- date -->
	
	<div class="meta-widget">
	<i class="fa fa-clock-o"></i>
	2015-07-10 
	</div>
	

	<!-- categories -->
    
	<div class="meta-widget">
	<a data-toggle="collapse" data-target="#categorys"><i class="fa fa-folder"></i></a>	
    <ul id="categorys" class="tag_box list-unstyled collapse in">
          
  <li>
    <li><a href="/categories/MySQL/">MySQL<span>1</span></a></li>
  </li>

    </ul>
	</div>
	

	<!-- tags -->
	
	<div class="meta-widget">
	<a data-toggle="collapse" data-target="#tags"><i class="fa fa-tags"></i></a>		  
    <ul id="tags" class="tag_box list-unstyled collapse in">	  
	    
  <li><a href="/tags/MySQL/">MySQL<span>1</span></a></li>
    </ul>
	</div>
		

	<!-- toc -->
	<div class="meta-widget">
	
	</div>
	
    <hr>
	
</div><!-- col-md-3 -->

	

</div><!-- row -->

	</div>
  </div>
  <div class="container-narrow">
  <footer> <p>
  &copy; 2015 Zhaifg
  
      with help from <a href="http://hexo.io/" target="_blank">Hexo</a> and <a href="http://getbootstrap.com/" target="_blank">Twitter Bootstrap</a>. Theme by <a href="http://github.com/wzpan/hexo-theme-freemind/">Freemind</a>.    
</p> </footer>
</div> <!-- container-narrow -->
  
<a id="gotop" href="#">   
  <span>▲</span> 
</a>

<script src="/js/jquery.imagesloaded.min.js"></script>
<script src="/js/gallery.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/main.js"></script>


<script type="text/javascript">
  var duoshuoQuery = { short_name: 'jenguo' };
  (function() {
    var ds = document.createElement('script');
    ds.type = 'text/javascript';
    ds.async = true;
    ds.src = 'http://static.duoshuo.com/embed.js';
    ds.charset = 'UTF-8';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
  })();
</script>


<link rel="stylesheet" href="/fancybox/jquery.fancybox.css" media="screen" type="text/css">
<script src="/fancybox/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
  $('.fancybox').fancybox();
})(jQuery);
</script>


</body>
   </html>
